﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net;
using System.Threading;
using System.Diagnostics;

namespace NielsDerdaele.HttpSocket.Windows {
    public class HttpSocketListener {
        private HttpListener listener;
        private Dictionary<string, HttpServerClientSocket> sockets = new Dictionary<string, HttpServerClientSocket>();
        public event EventHandler<EventArgs<HttpServerClientSocket>> NewHttpServerClientSocket;


        public HttpSocketListener() {
        }

        public void Start(string hostname, int port) {
            listener = new HttpListener();
            listener.Prefixes.Add("http://" + hostname + ":" + port + "/");            
            listener.Start();
            new Thread(new ThreadStart(listen)).Start();
        }
        private void listen() {
            while (true) {
                var context = listener.GetContext();
                new Thread(new ThreadStart(() => { processContext(context); })).Start(); //process request
            }
        }

        private void processContext(HttpListenerContext context) {            
            var type = context.Request.QueryString["type"];
            var uid = context.Request.QueryString["uid"];
            Console.WriteLine("NEW REQUEST \nTYPE: " + type);
            switch (type) {
                case "uid":
                    var guid = Guid.NewGuid().ToString();
                    var buffer = Encoding.UTF8.GetBytes(guid);
                    var hsc = new HttpServerClientSocket(guid);
                    context.Response.OutputStream.Write(buffer, 0, buffer.Length);
                    context.Response.Close();
                    OnNewHttpServerClientSocket(hsc);
                    break;
                case "callback":  //callback channel
                    if (String.IsNullOrWhiteSpace(uid)) {
                        context.Response.Close();
                    } else {
                        addCallbackChannelToClient(uid, context);
                    }
                    break;
                case "data"://data channel
                    if (String.IsNullOrWhiteSpace(uid)) {
                        context.Response.Close();
                    } else {
                        addDataToClient(uid, context);                        
                        context.Response.Close(); //TODO: toevoegen aan callback channels!
                    }
                    break;
                default: //fout!
                    context.Response.Close();
                    break;
            }
        }

        private void addCallbackChannelToClient(string uid, HttpListenerContext context) {
            var client = sockets[uid];
            if (client != null) {
                client.AddCallback(context);                
            } else {
                context.Response.Close();
            }
        }
        private void addDataToClient(string uid, HttpListenerContext context) {
            var client = sockets[uid];
            int id;
            if (client != null && int.TryParse(context.Request.QueryString["id"], out id)) {               
                List<byte> data = new List<byte>();
                byte[] buffer = new byte[256];
                Stream stream = context.Request.InputStream;
                int count = stream.Read(buffer, 0, buffer.Length);
                data.AddRange(buffer.Take(count));
                while (count > 0 && data.Count < context.Request.ContentLength64) {
                    count = stream.Read(buffer, 0, buffer.Length);
                }
                client.AddData(id, data.ToArray());                
            }
            context.Response.Close();
        }   
            
        protected virtual void OnNewHttpServerClientSocket(HttpServerClientSocket hsc) {
            sockets.Add(hsc.UniqueId, hsc);
            if (NewHttpServerClientSocket != null) {
                NewHttpServerClientSocket(this, new EventArgs<HttpServerClientSocket>(hsc));
            }
        }
    }
}
